home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue46 / Alfresco / AAGenExp.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-04-25  |  6.7 KB  |  237 lines

  1. {*********************************************************}
  2. {* AAGenExp                                              *}
  3. {* Copyright (c) Julian M Bucknall 1998-1999             *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Simple RPN routines                                   *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AAGenExp;
  14.  
  15. interface
  16.  
  17. type
  18.   ThwExpression = string[7];
  19.   ThwAlgebraicExpr = string[15];
  20.  
  21. type
  22.   ThwProcessExpression = procedure(const aExpr : ThwExpression);
  23.  
  24.  
  25. procedure GenerateExpressions(aProcessExpr : ThwProcessExpression);
  26.   {-Generate RPN expressions, calling aProcessExpr for each one}
  27.  
  28. function EvaluateExpression(const aExpr   : ThwExpression;
  29.                               var aAnswer : double) : boolean;
  30.   {-Evaluate an RPN expression where operands are single digits}
  31.  
  32. function ConvertExpression(const aExpr : ThwExpression) : ThwAlgebraicExpr;
  33.   {-Convert an RPN expression into an algebraic one, albeit with too
  34.     many parentheses in many cases}
  35.  
  36.  
  37. implementation
  38.  
  39. {===ConvertExpression================================================}
  40. function ConvertExpression(const aExpr : ThwExpression) : ThwAlgebraicExpr;
  41. var
  42.   i : integer;
  43.   SP : integer;
  44.   Value1 : ThwAlgebraicExpr;
  45.   Value2 : ThwAlgebraicExpr;
  46.   Stack : array [0..9] of ThwAlgebraicExpr;
  47.   Ch : char;
  48. begin
  49.   SP := 0;
  50.   for i := 1 to length(aExpr) do begin
  51.     Ch := aExpr[i];
  52.     if ('0' <= Ch) and (Ch <= '9') then begin
  53.       Stack[SP] := Ch;
  54.       inc(SP);
  55.     end
  56.     else begin
  57.       dec(SP); Value2 := Stack[SP];
  58.       dec(SP); Value1 := Stack[SP];
  59.       if (i < length(aExpr)) then
  60.         Stack[SP] := '(' + Value1 + Ch + Value2 + ')'
  61.       else
  62.         Stack[SP] := Value1 + Ch + Value2;
  63.       inc(SP);
  64.     end;
  65.   end;
  66.   dec(SP); Result := Stack[SP];
  67. end;
  68. {====================================================================}
  69.  
  70.  
  71. {===Helper routines for EvaluateExpression===========================}
  72. function Power(X, Y : double; var Answer : double) : boolean;
  73. begin
  74.   Result := true;
  75.   if (Y = 0.0) then
  76.     Answer := 1.0
  77.   else if (Y = 1.0) then
  78.     Answer := X
  79.   else if (X <= 0.0) then
  80.     Result := false
  81.   else
  82.     Answer := exp(ln(X) * Y);
  83. end;
  84. {====================================================================}
  85.  
  86.  
  87. {===EvaluateExpression===============================================}
  88. function EvaluateExpression(const aExpr   : ThwExpression;
  89.                               var aAnswer : double) : boolean;
  90. var
  91.   i : integer;
  92.   SP : integer;
  93.   Value1 : double;
  94.   Value2 : double;
  95.   Stack : array [0..9] of double;
  96.   Ch : char;
  97. begin
  98.   Result := false;
  99.   SP := 0;
  100.   for i := 1 to length(aExpr) do begin
  101.     Ch := aExpr[i];
  102.     {push operands}
  103.     if ('0' <= Ch) and (Ch <= '9') then begin
  104.       Stack[SP] := ord(Ch) - ord('0');
  105.       inc(SP);
  106.     end
  107.     {evaluate operators}
  108.     else begin
  109.       if (SP = 0) then Exit;
  110.       dec(SP); Value2 := Stack[SP];
  111.       if (SP = 0) then Exit;
  112.       dec(SP); Value1 := Stack[SP];
  113.       case Ch of
  114.         '-' : Stack[SP] := Value1 - Value2;
  115.         '+' : Stack[SP] := Value1 + Value2;
  116.         '*' : Stack[SP] := Value1 * Value2;
  117.         '/' : if (Value2 <> 0.0) then
  118.                 Stack[SP] := Value1 / Value2
  119.               else
  120.                 Exit;
  121.         '^' : if not Power(Value1, Value2, Stack[SP]) then
  122.                 Exit;
  123.       end;
  124.       inc(SP);
  125.     end;
  126.   end;
  127.   if (SP <> 1) then Exit;
  128.   dec(SP); aAnswer := Stack[SP];
  129.   Result := true;
  130. end;
  131. {====================================================================}
  132.  
  133.  
  134. {===Helper types, variables and routines for GenerateExpressions=====}
  135. type
  136.   String6 = string[6];
  137. var
  138.   Operators : string[5];
  139. {--------}
  140. procedure AddOperators(aProcess  : ThwProcessExpression;
  141.                    var aExpr     : ThwExpression);
  142. var
  143.   i, i1, i2, i3 : integer;
  144.   FirstBlank    : integer;
  145.   SecondBlank   : integer;
  146. begin
  147.   {find the first and second blanks; the third is always at 7}
  148.   FirstBlank := 0;
  149.   SecondBlank := 0;
  150.   for i := 3 to 6 do begin
  151.     if (aExpr[i] = ' ') then
  152.       if (FirstBlank = 0) then
  153.         FirstBlank := i
  154.       else begin
  155.         SecondBlank := i;
  156.         Break;
  157.       end;
  158.   end;
  159.   {replace the blanks with every combination of the operators}
  160.   for i1 := 1 to length(Operators) do begin
  161.     aExpr[FirstBlank] := Operators[i1];
  162.     for i2 := 1 to length(Operators) do begin
  163.       aExpr[SecondBlank] := Operators[i2];
  164.       for i3 := 1 to length(Operators) do begin
  165.         aExpr[7] := Operators[i3];
  166.         {process the completed RPN expression}
  167.         aProcess(aExpr);
  168.       end;
  169.     end;
  170.   end;
  171.   {reset the blanks: the permutation/replacement logic requires it}
  172.   aExpr[FirstBlank] := ' ';
  173.   aExpr[SecondBlank] := ' ';
  174.   aExpr[7] := ' ';
  175. end;
  176. {--------}
  177. procedure PermuteOperands(aProcess : ThwProcessExpression;
  178.                       var aExpr    : ThwExpression;
  179.                           aInx     : integer);
  180. var
  181.   i, j : integer;
  182.   Ch   : char;
  183. begin
  184.   if (aInx = 6) then begin
  185.     AddOperators(aProcess, aExpr);
  186.   end
  187.   else
  188.     for i := aInx to 6 do begin
  189.       Ch := aExpr[i];
  190.       aExpr[i] := aExpr[aInx];
  191.       aExpr[aInx] := Ch;
  192.       PermuteOperands(aProcess, aExpr, succ(aInx));
  193.       aExpr[aInx] := aExpr[i];
  194.       aExpr[i] := Ch;
  195.     end;
  196. end;
  197. {====================================================================}
  198.  
  199.  
  200. {===GenerateExpressions==============================================}
  201. procedure GenerateExpressions(aProcessExpr : ThwProcessExpression);
  202. var
  203.   Expr     : ThwExpression;
  204.   i1, i2   : integer;
  205.   Ch1, Ch2 : char;
  206.   Operands : String6;
  207. begin
  208.   {preset the expression string to the operands plus three spaces}
  209.   Expr := '2357   ';
  210.   Operators := '+-*/';
  211.   {generate the first token: an operand}
  212.   for i1 := 1 to 4 do begin
  213.     {swap characters 1 and i1}
  214.     Ch1 := Expr[i1];
  215.     Expr[i1] := Expr[1];
  216.     Expr[1] := Ch1;
  217.     {generate the second token: an operand}
  218.     for i2 := 2 to 4 do begin
  219.       {swap characters 2 and i2}
  220.       Ch2 := Expr[i2];
  221.       Expr[i2] := Expr[2];
  222.       Expr[2] := Ch2;
  223.       {permute tokens 3 thru 6}
  224.       PermuteOperands(aProcessExpr, Expr, 3);
  225.       {swap characters 2 and i2 back again}
  226.       Expr[2] := Expr[i2];
  227.       Expr[i2] := Ch2;
  228.     end;
  229.     {swap characters 1 and i1 back again}
  230.     Expr[1] := Expr[i1];
  231.     Expr[i1] := Ch1;
  232.   end;
  233. end;
  234. {====================================================================}
  235.  
  236. end.
  237.